#include "Lily_help.h"
#include <math.h>
#include "hashlib.h"


#define vvar (var->val)
int public_var(Var new_field)
{
	new_field->hashCode = getHashCodeS(new_field->name);
	return list_add(lily_ui.vars, new_field);
}

int32_t public_a_var_ref(const char *name, void *link, char type)
{
	Var_t var;
	var.name = (char*)name;

	var.val.pvoid = link;
	var.len = 0;
	var.type = toLower(type);
	var.isa = isUpper(type);
	var.isb = 1;
	var.isp = 1;
	return public_var(&var);
}

int32_t public_a_new_var(char *name, char type, void *val)
{
	if (!isLower(type))
		return -3;
	Var_t var;
	var.len = 0;
	var.isb = 0;
	var.isa = 0;
	var.isp = 0;

	var.name = (char *)malloc(strlen(name) + 1);

	assert_not_empty(var.name);
	strcpy((char *)(var.name), name);

	if (type == 's')
	{
		var.val.pvoid = new_string_by((char *)val);

		if (var.val.pvoid == NULL)
		{
			free(var.name);
			li_error("assign failed", -__LINE__);
		}
	}
	else
		var.val.pvoid = val;
	var.type = type;
	return public_var(&var);
}

int32_t public_new_vars_array(char *name, char type, void *val, int32_t len)
{
	Var_t var;
	var.isb = 0;
	var.isa = 1;
	var.isp = 1;

	var.name = (char *)malloc(strlen(name) + 1);

	assert_not_empty(var.name);
	strcpy((char *)(var.name), name);

	void *li = NULL;
	if (isLower(type))
		type = toUpper(type);
	switch (type)
	{
	case 'C':
		li = malloc(len);

		break;
	case 'F':
	case 'D':
	case 'S':
		li = malloc(len * 4);

		break;
	default:
		li_error("undefined type", -__LINE__);
	}

	assert_not_empty(li);

	if (type == 'C')
	{
		strncpy((char *)li, (char *)val, len);
	}
	else if (type == 'S')
	{
		int32_t i;
		for (i = 0; i < len; i++)
		{

			str s = new_string_by(val);
			((str *)li)[i] = s;
		}
	}
	else
	{
		int32_t i;
		for (i = len - 1; i; i--)
		{
			((int32_t *)li)[i] = (int32_t)val;
		}
		*((int32_t *)li) = (int32_t)val;
	}
	var.val.pvoid = li;
	var.type = toLower(type);
	var.len = len;
	return public_var(&var);
}

int32_t public_new_vars_array_by_string(char *name, char type, char *val, int32_t len)
{
	Var_t var;
	var.isb = 0;
	var.isa = 1;
	var.isp = 1;

	var.name = (char *)malloc(strlen(name) + 1);

	assert_not_empty(var.name);
	strcpy((char *)(var.name), name);

	void *li = NULL;
	type = toLower(type);

	int32_t xlen = 0;
	if (len > 0)
		xlen = len;
	float *nums = NULL;
	Li_List str_list = NULL;
	switch (type)
	{
	case 'c':
		if (!xlen)
			xlen = strlen(val);
		li = malloc(xlen);

		break;
	case 'f':
	case 'd':
	case 's':
		nums = get_nums_from_rx(val, &xlen);
		li = malloc(len > 0 ? len * 4 : xlen * 4);

		break;
	default:
		li_error("undefine type", -__LINE__);
	}
	assert_not_empty(li);

	int32_t i;
	switch (type)
	{
	case 'c':
		memcpy(li, val, xlen);
		break;
	case 'f':
		if (len > 0)
		{
			for (i = 0; i < len; i++)
			{
				if (i > xlen)
				{
					cast(li, float *)[i] = 0.0f;
				}
				else
				{
					cast(li, float *)[i] = nums[i];
				}
			}
		}
		else
		{
			memcpy(li, nums, xlen * 4);
		}
		break;
	case 'd':
		if (len > 0)
		{
			for (i = 0; i < len; i++)
			{
				if (i > xlen)
				{
					cast(li, int32_t *)[i] = 0.0f;
				}
				else
				{
					cast(li, int32_t *)[i] = nums[i];
				}
			}
		}
		else
		{
			for (i = 0; i < xlen; i++)
			{
				cast(li, int32_t *)[i] = nums[i];
			}
		}
		break;
	case 's':
		str_list = str_split(val, ' ');
		assert_not_empty(str_list);
		str *ss = cast(str_list->content, str *);
		xlen = str_list->count;

		if (len > 0)
		{
			for (i = 0; i < len; i++)
			{
				if (i >= xlen)
				{
					((str *)li)[i] = NULL;
					continue;
				}

				((str *)li)[i] = new_string_by(ss[i]);
				if (((str *)li)[i] == NULL)
				{
					delete_list(str_list);
					li_error("memory out", -__LINE__);
				}
			}
		}
		else
		{
			for (i = 0; i < xlen; i++)
			{
				((str *)li)[i] = new_string_by(ss[i]);
				if (((str *)li)[i] == NULL)
				{
					delete_list(str_list);
					li_error("memory out", -__LINE__);
				}
			}
		}
		delete_list(str_list);
		break;
	default:
		break;
	}
	var.val.pvoid = li;
	var.type = type;
	var.len = len > 0 ? len : xlen;
	return public_var(&var);
}

void *get_value_of_var(Var var, int32_t at)
{
	void *val;
	switch (var->type)
	{
	case 'f':
	case 'd':
		if (var->isa)
		{
			val = cast(var->val.pi[at], void *);
		}
		else
		{
			val = var->isp ? cast(*(var->val.pi), void *) : cast(var->val.vi, void *);
		}
		break;
	case 'c':
		if (var->isa)
		{
			val = cast(var->val.pc[at], void *);
		}
		else
		{
			val = var->isp ? cast(*(var->val.pc), void *) : cast(var->val.vc, void *);
		}
		break;
	case 's':
		if (var->isa)
		{
			val = cast(var->val.ps[at], void *);
		}
		else
		{
			val = var->isp ? cast(*(var->val.ps), void *) : cast(var->val.vs, void *);
		}
		break;
	default:
		return NULL;
	}
	return val;
}

int32_t set_value_of_var(Var var, int32_t at, void *val)
{
	switch (var->type)
	{
	case 'f':
	case 'd':
		if (var->isa)
		{
			if (!var->isb && at >= var->len)
				return -4;

			var->val.pi[at] = void_to_int(val);
		}
		else
		{
			if (at)
				return -2;
			if (var->isp)
			{
				*vvar.pi = void_to_int(val);
			}
			else
				vvar.vi = (int32_t)val;
		}
		break;
	case 'c':
		if (var->isa)
		{
			if (!var->isb && at >= var->len)
				return -4;
			vvar.pc[at] = cast(val, char);
		}
		else
		{
			if (at)
				return -3;
			if (var->isp)
			{
				*(vvar.pc) = cast(val, char);
			}
			else
				vvar.vc = cast(val, char);
		}
		break;
	case 's':
		if (var->isa)
		{
			if (!var->isb && at >= var->len)
				return -4;
			vvar.ps[at] = cast(val, str);
		}
		else
		{
			if (at)
				return -3;
			if (var->isp)
			{
				*(vvar.ps) = cast(val, str);
			}
			else
				vvar.vs = cast(val, str);
		}
		break;
	default:
		return -1;
	}
	return 0;
}

int32_t delete_a_var(Var var)
{
	if (var->isb)
	{
		li_error("protected", -__LINE__);
	}
	free((void *)(var->name));

	if (var->isa)
	{
		if (var->type == 's')
		{
			int32_t i;
			for (i = 0; i < var->len; i++)
			{
				free(vvar.ps[i]);
			}
		}
		free(vvar.pvoid);
	}
	else if (var->type == 's')
	{
		free(vvar.pc);
	}
	return 0;
}

int32_t search_var_in_Lily_ui(const char *item)
{
	int32_t i, n;
	n = lily_ui.vars->count;
	Var fields = li_vars;
	uint32_t hc1 = getHashCodeS(item);
	for (i = 0; i < n; i++)
	{
		if (hc1 != fields[i].hashCode)
			continue;
		if (strcmp(item, fields[i].name))
			continue;
		return i;
	}
	return -1;
}

Pipe pipe_out_to_str_var = NULL;

void *redirection_out_append_to_var(void *arg, const char *s, int32_t len)
{
	/*if (pipe_var == NULL)return;
	if (pipe_var->val.vs == NULL)
	{
		pipe_var->val.vs = new_string_by(s);
	}
	else
	{*/
	if (!arg || !len)
		return NULL;
	str *pipe_out_str = arg;
	char *p = dynamic_str_cat(*pipe_out_str, s);
	if (p != NULL)
	{
		*pipe_out_str = p;
	}
	return NULL;
}

int32_t _test_redirection_output_to_var(char *rx)
{
	int32_t ind = str_index_right(rx, '>');
	if (ind < 0)
		return 0;
	str *pipe_out_str = NULL;

	int32_t i = ind + 1;
	while (rx[i] == ' ')
		i++;
	if (rx[i] == '\0')
	{

		pipe_disconnect(lily_ui.lily_std_pipe);
		rx[ind] = '\0';
		return ind;
	}

	str srx = rx + i;
	int32_t bbc = str_index(srx, '[');
	int32_t at = -1;
	if (bbc >= 0)
	{
		srx[bbc] = '\0';
		if (!str_is_name(srx))
			return 0;
		srx[bbc] = '[';

		at = _ebrace_value_from_string(srx);
		if (at < -1)
		{
			return 0;
		}
		if (at == -1)
			at = 0;
	}
	else
	{
		if (!str_is_name(srx))
			return 0;
	}

	char append = 0;
	if (rx[ind - 1] == '>')
	{
		rx[ind - 1] = '\0';
		append = 1;
	}
	else
	{
		rx[ind] = '\0';
	}
	rx += i;

	Pipe p_dir = pipe_find(rx);
	if (p_dir)
	{
		lily_redirect_output(p_dir);
	}
	else
	{
		int32_t var_ind = search_var_in_Lily_ui(rx);
		if (var_ind < 0)
		{

			if (append)
				rx[ind - 1] = '>';
			else
				rx[ind] = '>';
			return 0;
		}
		Var var = li_vars + var_ind;
		if (var->type != 's' || (at >= 0 && !var->isa) || var->len <= at)
		{

			if (append)
				rx[ind - 1] = '>';
			else
				rx[ind] = '>';
			return 0;
		}

		if (at < 0 && var->isa)
		{
			at = 0;
		}

		if (at >= 0)
			pipe_out_str = var->val.ps + at;
		else
			pipe_out_str = &(var->val.vs);
		if (!append)
		{
			if (at >= 0)
			{
				if (*pipe_out_str == NULL)
				{
					*pipe_out_str = new_string_by("");
				}
				else
				{
					(*pipe_out_str)[0] = '\0';
				}
			}
			else
			{
				_assign_string_var(var, "");
			}
		}
		pipe_out_to_str_var->arg = pipe_out_str;
		lily_redirect_output(pipe_out_to_str_var);
	}

	if (append)
		return ind - 1;
	return ind;
}

#undef vvar
